import qs from 'qs'
import uuid from '@/utils/uuid'

import storage from '@/utils/storage'
import { revoke } from '@/api/oauth2'

async function sha256HashAndBase64UrlEncode(codeVerifier) {
  // 将 codeVerifier 转换为 ArrayBuffer
  const encoder = new TextEncoder()
  const data = encoder.encode(codeVerifier)

  // 计算 SHA-256 哈希值
  const hashBuffer = await crypto.subtle.digest('SHA-256', data)
  const hashArray = Array.from(new Uint8Array(hashBuffer))

  // 将哈希值转换为字符串
  const hashString = String.fromCharCode.apply(null, hashArray)

  // 进行 Base64 编码
  let base64 = btoa(hashString)

  // 将 '+' 替换为 '-'，'/' 替换为 '_'，并去掉 '='
  const base64Url = base64
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=+$/, '')

  return base64Url
}

const state = () => ({
  codeVerifier: storage.get('codeVerifier'),
  code: storage.get('code'),
  token: storage.get('token') || {},
})

const mutations = {
  SET_CODE_VERIFIER(state, codeVerifier) {
    storage.set('codeVerifier', codeVerifier)
    state.codeVerifier = codeVerifier
  },
  CLEAR_CODE_VERIFIER(state) {
    storage.remove('codeVerifier')
    state.codeVerifier = null
  },
  SET_CODE(state, code) {
    storage.set('code', code)
    state.code = code
  },
  CLEAR_CODE(state) {
    storage.remove('code')
    state.code = null
  },
  SET_TOKEN(state, token) {
    storage.set('token', token)
    state.token = token
  },
  CLEAR_TOKEN(state) {
    storage.remove('token')
    state.token = {}
  },
}

const actions = {
  gotoAuthCenter({ commit }) {
    commit('CLEAR_CODE_VERIFIER')
    commit('CLEAR_CODE')
    commit('CLEAR_ACCESS_TOKEN')

    const codeVerifier = uuid()
    commit('SET_CODE_VERIFIER', codeVerifier)

    let scopes = window.client.scope.split(' ')
    for (let i in scopes) {
      scopes[i] = encodeURIComponent(scopes[i])
    }

    sha256HashAndBase64UrlEncode(codeVerifier).then((code_challenge) => {
      const params = {
        client_id: window.client.clientId,
        response_type: 'code',
        redirect_uri: window.client.redirectUri,
        code_challenge,
        code_challenge_method: 'S256',
        scope: scopes.join(' '),
      }

      const url = window.client.authCenterUrl + '?' + qs.stringify(params)
      window.location.href = url
    })
  },
  tokenRevoke({ state, commit }) {
    revoke({
      client_id: window.client.clientId,
      code_verifier: state.codeVerifier,
      token: state.token.access_token,
      grant_type: 'authorization_code',
      code: state.code,
    }).then(() => {
      commit('CLEAR_CODE_VERIFIER')
      commit('CLEAR_CODE')
      commit('CLEAR_ACCESS_TOKEN')
    })
  },
}

export default {
  namespaced: true,
  state: state,
  actions: actions,
  mutations: mutations,
}
